package cn.com.twoke.game.client.games.tic_tac_toe.controller;

import cn.com.twoke.game.client.GameClientManager;
import cn.com.twoke.game.client.games.framework.ui.ChatMessage;
import cn.com.twoke.game.client.games.tic_tac_toe.TicTacToeGame;
import cn.com.twoke.game.client.games.tic_tac_toe.constants.TicTacToeChess;
import cn.com.twoke.game.client.games.tic_tac_toe.constants.TicTacToeGameConstant;

import javax.swing.*;
import java.awt.*;


public class RobotChessController implements ChessController, TicTacToeGameConstant {
    private static final int MAX_DEPTH = 9;
    private int[][] board = new int[ROW][COL];
    private int[][] score = new int[ROW][COL];

    private TicTacToeGame game;


    @Override
    public void setGame(TicTacToeGame ticTacToeGame) {
        this.game = ticTacToeGame;
    }

    @Override
    public void drop(int x, int y) {
        this.game.drop(x, y);
        if (this.game.checkWin(x, y, this.game.getUserDropingChessType())) {
            JOptionPane.showMessageDialog(this.game.getWindow(), "玩家获胜!");
            this.game.resetGame();
            return;
        }
        for (int _y = 0; _y < ROW; _y++) {
            for (int _x = 0; _x < COL; _x++) {
                board[_y][_x] =this.game.getGrid()[_y][_x].getType().getCode();
            }
        }
        if (isGameOver()) {
            JOptionPane.showMessageDialog(this.game.getWindow(), "平局!");
            this.game.resetGame();
            return;
        }
        new Thread(() -> {

            aiMove();
            this.game.setCanDropChess(true);
        }).start();
    }

    @Override
    public void sendMessage(String content) {
        this.game.acceptMessage(new ChatMessage(content, this.game.getPlayerName(), System.currentTimeMillis()));
    }

    @Override
    public void undo() {
        this.game.getChessNotes().pop().setType(TicTacToeChess.Type.NONE);
        this.game.getChessNotes().pop().setType(TicTacToeChess.Type.NONE);
    }

    @Override
    public void gameOver() {
        // 退出系统
        int i = JOptionPane.showConfirmDialog(this.game.getWindow(),
                "确认要结束游戏？"
        );
        if (i == JOptionPane.OK_OPTION) {
            if (this.game.isNetwork()) {
                GameClientManager.INSTANCE.stopGame(TicTacToeGame.ID, this.game.getRoomId(), this.game.getPlayerName());
            } else {
                System.exit(0);
            }
        }
    }

    private void aiMove() {
        Point bestMove = findBestMove();
        if (bestMove!= null) {
            this.game.drop(bestMove.x, bestMove.y, this.game.getNotUserDropingChessType()); // 机器下白棋
            if (this.game.checkWin(bestMove.x, bestMove.y, this.game.getNotUserDropingChessType())) {
                JOptionPane.showMessageDialog(this.game.getWindow(), "机器获胜!");
                this.game.resetGame();
            } else if (isGameOver()) {
                JOptionPane.showMessageDialog(this.game.getWindow(), "平局!");
                this.game.resetGame();
            }
        }
    }

    private Point findBestMove() {
        int bestScore = Integer.MIN_VALUE;
        int alpha = Integer.MIN_VALUE;
        int beta = Integer.MAX_VALUE;
        Point bestMove = null;
        for (int x = 0; x < 3; x++) {
            for (int y = 0; y < 3; y++) {
                if (board[y][x] == 0) {
                    board[y][x] = this.game.getNotUserDropingChessType().getCode(); // 假设机器落子
                    int score = minimax(alpha, beta, 0, false);
                    this.score[y][x] = score;
                    board[y][x] = 0; // 撤销落子
                    if (score > bestScore) {
                        bestScore = score;
                        System.out.println("bestScore  ("+x+","+y+")");
                        bestMove = new Point(x, y);
                    }
                }
            }
        }
        for (int y = 0; y < 3; y++) {
            for (int x = 0; x < 3; x++) {
                System.out.print("(" + x + "," + y + ")=" + score[y][x] + " ");
            }
            System.out.println();
        }
        return bestMove;

    }

    private int checkLine(int[] line, int player) {
        int otherPlayer = player == 1 ? -1 : 1;
        int oCount = 0;
        int pCount = 0;
        int emptyCount = 0;
        for (int i = 0; i < line.length; i++) {
            if (line[i] == player) {
                pCount++;
            } else if (line[i] == otherPlayer) {
                oCount++;
            } else {
                emptyCount++;
            }
        }
        if (pCount == 3) {
            return 100;
        }
        if (oCount == 3) {
            return -100;
        }

        if (pCount == 2 && oCount == 1) {
            return 5;
        }
        if (oCount == 2 && pCount == 1) {
            return -5;
        }

        if (pCount == 2 && emptyCount == 1) {
            return 5;
        }
        if (oCount == 2 && emptyCount == 1) {
            return -5;
        }
        return 0;
    }

    private int evaluate() {
        int score = 0;

        for (int i = 0; i < 3; i++) {
            score += checkLine(new int[]{
                    board[i][0],
                    board[i][1],
                    board[i][2]
            }, this.game.getNotUserDropingChessType().getCode());
        }
        for (int i = 0; i < 3; i++) {
            score += checkLine(new int[]{
                    board[0][i],
                    board[1][i],
                    board[2][i]
            }, this.game.getNotUserDropingChessType().getCode());
        }

        score += checkLine(new int[]{
                board[0][0],
                board[1][1],
                board[2][2]
        }, this.game.getNotUserDropingChessType().getCode());


        score += checkLine(new int[]{
                board[2][0],
                board[1][1],
                board[0][2]
        }, this.game.getNotUserDropingChessType().getCode());

        return score;
    }

    private int evaluatePlayer(int code) {
        int playerScore = 0;
        // 检查横向
        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 3; j++) {
                int[] pattern = new int[3];
                int count = 0;
                for (int k = 0; k < 3 && j + k < 3; k++) {
                    pattern[k] = board[i][j + k];
                    count++;
                }
                if (count < 3) {
                    continue;
                }
                playerScore += scorePattern(pattern, code);
            }
        }
        // 检查纵向
        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 3; j++) {
                int[] pattern = new int[3];
                int count = 0;
                for (int k = 0; k < 3 && i + k < 3; k++) {
                    pattern[k] = board[i + k][j];
                    count++;
                }
                if (count < 3) {
                    continue;
                }
                playerScore += scorePattern(pattern, code);
            }
        }
        // 检查正斜向
        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 3; j++) {
                int[] pattern = new int[3];
                int count = 0;
                for (int k = 0; k < 3 && i + k < 3 && j + k < 3; k++) {
                    pattern[k] = board[i + k][j + k];
                    count++;
                }
                if (count < 3) {
                    continue;
                }
                playerScore += scorePattern(pattern, code);
            }
        }
        // 检查反斜向
        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 3; j++) {
                int[] pattern = new int[3];
                int count = 0;
                for (int k = 0; k < 3 && i - k >= 0 && j + k < 3; k++) {
                    pattern[k] = board[i - k][j + k];
                    count++;
                }
                if (count < 3) {
                    continue;
                }
                playerScore += scorePattern(pattern, code);
            }
        }
        return playerScore;
    }

    private int scorePattern(int[] pattern, int player) {
        int opponent = player == 1 ? -1 : 1;
        int playerCount = 0;
        int opponentCount = 0;
        int emptyCount = 0;


        for (int p : pattern) {
            if (p == player) playerCount++;
            else if (p == opponent) opponentCount++;
            else emptyCount++;
        }


        if (playerCount == 3) return 100000;
        if (opponentCount == 3) return -100000;

        if (playerCount == 2 && opponentCount == 1) return -1000;
        if (playerCount == 1 && opponentCount == 2) return 1000;

        // 不同棋型的得分
        if (playerCount == 2 && emptyCount == 1) return 20; // 活二
        if (playerCount == 1 && emptyCount == 2) return 10; // 活一

        if (opponentCount == 2 && emptyCount == 1) return -20; // 对手活二
        if (opponentCount == 1 && emptyCount == 2) return -10; // 对手活一

        return 0;
    }

    private int minimax(int alpha, int beta, int depth, boolean isMaximizingPlayer) {
        if (depth == MAX_DEPTH || isGameOver()) {
            return evaluate();
        }
        if (isMaximizingPlayer) {
            int bestScore = Integer.MIN_VALUE;
            for (int i = 0; i < 3; i++) {
                for (int j = 0; j < 3; j++) {
                    if (board[i][j] == 0) {
                        board[i][j] = this.game.getNotUserDropingChessType().getCode(); // 机器落子
                        int move = minimax(alpha, beta,depth + 1, false);
                        board[i][j] = 0; // 撤销落子
                        if (move > bestScore) {
                            bestScore = move;
                        }
                        alpha = Math.max(alpha, bestScore);
                        if (beta <= alpha) {
                            break;
                        }
                    }
                }
            }
            return bestScore;
        } else {
            int bestScore = Integer.MAX_VALUE;
            for (int i = 0; i < 3; i++) {
                for (int j = 0; j < 3; j++) {
                    if (board[i][j] == 0) {
                        board[i][j] = this.game.getUserDropingChessType().getCode(); // 玩家落子
                        System.out.println("beta:" + beta);
                        int move = minimax(alpha, beta,depth + 1, true);
                        board[i][j] = 0; // 撤销落子
                        if (move < bestScore) {
                            bestScore = move;
                        }
                        beta = Math.min(bestScore, beta);
                        if (beta <= alpha) {
                            break;
                        }
                    }
                }
            }
            return bestScore;
        }
    }

    private boolean isGameOver() {
        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 3; j++) {
                if (board[i][j] == 0) return false;
            }
        }
        return true;
    }

}
